// @ts-nocheck
import { proxy, subscribe, useSnapshot } from 'valtio';
import { isChanged } from 'proxy-compare';

function defineProperties(target, props) {
  for (let i = 0; i < props.length; i++) {
    const descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ('value' in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor);
  }
}

function defineProperty(obj, key, value) {
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value,
      enumerable: true,
      configurable: true,
      writable: true,
    });
  } else {
    obj[key] = value;
  }
  return obj;
}

function createClass(Constructor, protoProps, staticProps) {
  if (protoProps) defineProperties(Constructor.prototype, protoProps);
  if (staticProps) defineProperties(Constructor, staticProps);
  Object.defineProperty(Constructor, 'prototype', {
    writable: false,
  });
  return Constructor;
}

const BabelObj = (function () {
  function Obj() {
    // defineProperty(this, "id", Math.random());
    // can be executed but cannot trigger re-render
    console.log('Obj constructor');
  }
  createClass(Obj, [
    {
      key: 'getId',
      value: function getId() {
        return Math.random();
      },
    },
  ]);
  return Obj;
})();

// const Obj = OldObj;
const ObjClass = (function () {
  const Obj2 = function () {
    // defineProperty(this, "id", Math.random());
    console.log('custom Class constr');
    // this.getId = ()=>Math.random();
  };

  Object.defineProperty(Obj2.prototype, 'getId', {
    value: function getId() {
      return Math.random();
    },
    // enumerable: true,
    // configurable: true,
    // writable: true
    // writable: false
  });
  return Obj2;
})();

// Object.defineProperty(Obj2, "prototype", {
//   writable: false
// });

class Obj {
  constructor() {
    // can be executed but cannot trigger re-render
    console.log('Obj constructor');
  }

  // id = Math.random();

  getId() {
    return Math.random();
  }
}

const data = proxy({
  obj: new Obj(),
  changeGetIdByMyClass() {
    // cannot trigger rerender

    const obj = new ObjClass();

    //  {
    //   // id: Math.random(),
    //   // getId: () => Math.random()
    // };
    // Object.defineProperty(this.obj, "id", {
    //   value: Math.random(),
    //   writable: false
    // });

    this.obj = obj;
  },
  changeGetIdByBabel() {
    // can trigger rerender
    this.obj = new BabelObj();
  },
  changeGetIdByOOP() {
    // can trigger rerender
    this.obj = new Obj();
  },
});

const ref: Record<string, any> = {};
subscribe(data, () => {
  console.log(
    '数据变化',
    isChanged(ref.last, data.obj, new WeakMap(), new WeakMap()),
    ref.last,
    data.obj
  );
  ref.last = data.obj;
});

const Test = () => {
  const snap = useSnapshot(data);
  // const id1 = snap.obj?.id;
  const id2 = snap.obj?.getId?.();

  // 会访问所有的属性
  // console.log(JSON.stringify(snap.obj));
  return (
    <div>
      <button
        onClick={() => {
          data.changeGetIdByMyClass();
        }}
      >
        changeGetIdByMyClass
      </button>
      <button
        onClick={() => {
          data.changeGetIdByOOP();
        }}
      >
        changeGetIdByOOP
      </button>
      <button
        onClick={() => {
          data.changeGetIdByBabel();
        }}
      >
        changeGetIdByBabel
      </button>
      {/* {id1} */}
      {id2}
    </div>
  );
};

export default Test;
